import com.alibaba.fastjson.JSON;
import com.itheima.demo.Goods;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ElasticDemo {

    private RestHighLevelClient client;

    /**
     * 建立连接
     */
    @Before
    public void init() throws IOException {
        client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("192.168.206.99", 9200, "http")
                )
        );
    }

    /**
     * 关闭客户端连接
     */
    @After
    public void close() throws IOException {
        client.close();
    }


    @Test
    public void testCreateIndex() throws IOException {
        CreateIndexRequest request = new CreateIndexRequest("goods");
        request.source("{\n" +
                "  \"settings\": {\n" +
                "    \"analysis\": {\n" +
                "      \"analyzer\": {\n" +
                "        \"my_pinyin\": {\n" +
                "          \"tokenizer\": \"ik_smart\",\n" +
                "          \"filter\": [\n" +
                "            \"py\"\n" +
                "          ]\n" +
                "        }\n" +
                "      },\n" +
                "      \"filter\": {\n" +
                "        \"py\": {\n" +
                "          \"type\": \"pinyin\",\n" +
                "          \"keep_full_pinyin\": false,\n" +
                "          \"keep_joined_full_pinyin\": true,\n" +
                "          \"keep_original\": true,\n" +
                "          \"limit_first_letter_length\": 16,\n" +
                "          \"remove_duplicated_term\": true\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  },\n" +
                "  \"mappings\": {\n" +
                "    \"properties\": {\n" +
                "      \"id\": {\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"name\": {\n" +
                "        \"type\": \"completion\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"title\":{\n" +
                "        \"type\": \"text\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"price\":{\n" +
                "        \"type\": \"long\"\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "}", XContentType.JSON);
        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
        System.out.println("response = " + response.isAcknowledged());
    }

    @Test
    public void testBulkDocument() throws IOException {
        List<Goods> list = new ArrayList<>();
        list.add(new Goods(1L, "红米9", "红米9手机 数码", 1499L));
        list.add(new Goods(2L, "三星 Galaxy A90", "三星 Galaxy A90 手机 数码 疾速5G 骁龙855", 3099L));
        list.add(new Goods(3L, "Sony WH-1000XM3", "Sony WH-1000XM3 降噪耳机 数码", 2299L));
        list.add(new Goods(4L, "松下剃须刀", "松下电动剃须刀高转速磁悬浮马达", 599L));
        BulkRequest bulkRequest = new BulkRequest();
        list.forEach(goods -> {
            bulkRequest.add(
                    new IndexRequest("goods")
                            .id(goods.getId().toString())
                            .source(JSON.toJSONString(goods), XContentType.JSON));
        });
        BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println("response = " + response.status());
    }

    @Test
    public void testBasicSearchWithSortAndPage() throws IOException, InvocationTargetException, IllegalAccessException {
        SearchRequest request = new SearchRequest("goods");
        SearchSourceBuilder sourBuilder = new SearchSourceBuilder();
        int page = 1, size = 5;
        int from  = (page - 1) * size;
        sourBuilder.fetchSource(new String[0], new String[]{"name"})
                .query(QueryBuilders.boolQuery()
                        .must(QueryBuilders.matchQuery("title", "数码"))
                        .filter(QueryBuilders.rangeQuery("price").lte(3000)))
                .sort("price", SortOrder.ASC)
                .from(from)
                .size(size)
                .highlighter(new HighlightBuilder().field("title"));
        request.source(sourBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits searchHits = response.getHits();
        long value = searchHits.getTotalHits().value;
        for (SearchHit hit : searchHits.getHits()) {
            String source = hit.getSourceAsString();
            Goods goods = JSON.parseObject(source, Goods.class);
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            for (HighlightField highlightField : highlightFields.values()) {
                String fieldName = highlightField.getName();
                String fieldValue = StringUtils.join(highlightField.getFragments());
                BeanUtils.setProperty(goods,fieldName,fieldValue);
            }
            System.out.println("goods = " + goods);
        }
    }

    @Test
    public void testSuggest() throws IOException {
        SearchRequest request = new SearchRequest("goods");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.suggest(new SuggestBuilder().addSuggestion("name_suggest", SuggestBuilders.completionSuggestion("name").prefix("s").size(30)));
        request.source(sourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        Suggest suggest = response.getSuggest();
        Suggest.Suggestion<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> name_suggest = suggest.getSuggestion("name_suggest");
        for (Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option> entry : name_suggest) {
            List<? extends Suggest.Suggestion.Entry.Option> options = entry.getOptions();
            System.out.println("======================");
            for (Suggest.Suggestion.Entry.Option option : options) {
                Text text = option.getText();
                System.out.println("text = " +"\t"+ text);
            }

        }

    }

    @Test
    public void testAsyncAddDocument() throws InterruptedException {
        Goods goods = new Goods(5L, "松下电吹风", "松下电吹风 网红电吹风", 1599L);
        IndexRequest request = new IndexRequest("goods");
        request.id(goods.getId().toString())
                .source(JSON.toJSONString(goods),XContentType.JSON);
        client.indexAsync(request, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() {
            @Override
            public void onResponse(IndexResponse indexResponse) {
                System.out.println("success");
                System.out.println("==================");
                System.out.println("indexResponse = " + indexResponse);
            }

            @Override
            public void onFailure(Exception e) {
                System.out.println("e = " + e);
            }
        });

        System.out.println("调用完成");
        Thread.sleep(1000);
    }


    @Test
    public void testAsyncDeleteDocument() throws InterruptedException {
        client.deleteAsync(new DeleteRequest("goods", "5"), RequestOptions.DEFAULT, new ActionListener<DeleteResponse>() {
            @Override
            public void onResponse(DeleteResponse deleteResponse) {
                System.out.println("deleteResponse = " + deleteResponse.status());
            }

            @Override
            public void onFailure(Exception e) {
                System.out.println("======================");
            }
        });

        Thread.sleep(1000);
    }

    @Test
    public void testGetDocumentByIdAsync() throws IOException, InterruptedException {

        client.getAsync(new GetRequest("goods", "1"), RequestOptions.DEFAULT, new ActionListener<GetResponse>() {
            @Override
            public void onResponse(GetResponse documentFields) {
                System.out.println("documentFields = " + documentFields.getSourceAsString());
            }

            @Override
            public void onFailure(Exception e) {

            }
        });
        Thread.sleep(1000);
    }

}